package com.bn.feed;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.ejb.CreateException;
import javax.ejb.EJBException;

import atg.core.util.StringUtils;
import atg.deployment.server.AgentRef;
import atg.deployment.server.Deployment;
import atg.deployment.server.DeploymentServer;
import atg.deployment.server.Target;
import atg.dtm.TransactionDemarcationException;
import atg.epub.project.Process;
import atg.epub.project.ProcessHome;
import atg.epub.project.Project;
import atg.epub.project.ProjectConstants;
import atg.epub.project.ProjectHome;
import atg.nucleus.GenericService;
import atg.process.action.ActionConstants;
import atg.process.action.ActionException;
import atg.repository.Query;
import atg.repository.QueryBuilder;
import atg.repository.QueryExpression;
import atg.repository.Repository;
import atg.repository.RepositoryItem;
import atg.repository.RepositoryView;
import atg.security.Persona;
import atg.security.ThreadSecurityManager;
import atg.security.User;
import atg.security.UserAuthority;
import atg.versionmanager.VersionManager;
import atg.versionmanager.WorkingContext;
import atg.versionmanager.Workspace;
import atg.versionmanager.exceptions.VersionException;
import atg.workflow.ActorAccessException;
import atg.workflow.MissingWorkflowDescriptionException;
import atg.workflow.OutcomeDescriptor;
import atg.workflow.TaskDescriptor;
import atg.workflow.WorkflowConstants;
import atg.workflow.WorkflowDescriptor;
import atg.workflow.WorkflowException;
import atg.workflow.WorkflowManager;
import atg.workflow.WorkflowView;
import atg.workflow.WorkflowViewImpl;

/**
 * This class is used to create the Workflow in BCC.
 */
public class WorkFlowTools extends GenericService {

    /**
     * Holds the processes size limit.
     */
    public static final int PROCESSES_SIZE_LIMIT = 1;

	/**
	 * Holds the default task id.
	 */
	private String mDefaultTaskId;

	/**
	 * Holds the VersionManager service.
	 */
	private VersionManager mVersionManager;

    /**
     * Holds the UserAuthority component.
     */
    private UserAuthority mUserAuthority;

    /**
     * Holds de PersonaPrefix.
     */
    private String mPersonaPrefix;

    /**
     * Holds the workflowManager component.
     */
    private WorkflowManager workflowManager;

    /**
     * Holds the taskListForAutoPublish.
     */
    private List<String> taskListForAutoPublish;

    /**
     * Holds the common workFlowName wdl.
     */
    private String workFlowName;

    /**
     * Holds the workFlowNameForAutomaticPublish wdl.
     */
    private String workFlowNameForAutomaticPublish;

    /**
     * Holds the user name.
     */
    private String userName;

    /**
     * Holds the deploymentServer component.
     */
    private DeploymentServer deploymentServer;


    /**
     * Holds the PublishingRepository component.
     */
    private Repository publishingRepository;

    /**
     * Production target name.
     */
    private static final String PRODUCTION_TARGET = "Production";

    /**
     * Staging target name.
     */
    private static final String STAGING_TARGET = "Staging";

    // Gets & Sets

	/**
	 * @return the mDefaultTaskId
	 */
	public String getDefaultTaskId() {
		return mDefaultTaskId;
	}

	/**
	 * @param pDefaultTaskId the pDefaultTaskId to set
	 */
	public void setDefaultTaskId(final String pDefaultTaskId) {
		this.mDefaultTaskId = pDefaultTaskId;
	}

    /**
     * Used to get the VersionManager.
     *
     * @return VersionManager
     */
    public VersionManager getVersionManager() {
        return mVersionManager;
    }

    /**
     * Used to sets the VersionManager.
     *
     * @param pVersionManager
     *            - The versionManager object
     */
    public void setVersionManager(final VersionManager pVersionManager) {
        mVersionManager = pVersionManager;
    }

    /**
     * Used to get the UserAuthority.
     *
     * @return mUserAuthority
     */
    public UserAuthority getUserAuthority() {
        return mUserAuthority;
    }

    /**
     * Used to set the UserAuthority.
     *
     * @param pUserAuthority
     *            - The UserAuthority to set
     */
    public void setUserAuthority(final UserAuthority pUserAuthority) {
        mUserAuthority = pUserAuthority;
    }

    /**
     * Used to get the PerosnPrefix.
     *
     * @return mPersonaPrefix
     */
    public String getPersonaPrefix() {
        return mPersonaPrefix;
    }

    /**
     * Used to set the PersonaPrefix.
     *
     * @param pPersonaPrefix
     *            - The persona prefix to set
     */
    public void setPersonaPrefix(final String pPersonaPrefix) {
        mPersonaPrefix = pPersonaPrefix;
    }

    /**
     * @return the workflowManager
     */
    public WorkflowManager getWorkflowManager() {
        return workflowManager;
    }

    /**
     * @param workflowManager
     *            the workflowManager to set
     */
    public void setWorkflowManager(final WorkflowManager workflowManager) {
        this.workflowManager = workflowManager;
    }

    /**
     * @return the taskListForAutoPublish
     */
    public List<String> getTaskListForAutoPublish() {
        return taskListForAutoPublish;
    }

    /**
     * @param taskListForAutoPublish
     *            the taskListForAutoPublish to set
     */
    public void setTaskListForAutoPublish(final List<String> taskListForAutoPublish) {
        this.taskListForAutoPublish = taskListForAutoPublish;
    }

    /**
     * @return the workFlowName
     */
    public String getWorkFlowName() {
        return workFlowName;
    }

    /**
     * @param workFlowName
     *            the workFlowName to set
     */
    public void setWorkFlowName(final String workFlowName) {
        this.workFlowName = workFlowName;
    }

    /**
     * @return the workFlowNameForAutomaticPublish
     */
    public String getWorkFlowNameForAutomaticPublish() {
        return workFlowNameForAutomaticPublish;
    }

    /**
     * @param workFlowNameForAutomaticPublish
     *            the workFlowNameForAutomaticPublish to set
     */
    public void setWorkFlowNameForAutomaticPublish(final String workFlowNameForAutomaticPublish) {
        this.workFlowNameForAutomaticPublish = workFlowNameForAutomaticPublish;
    }

    /**
     * @return the userName
     */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName
     *            the userName to set
     */
    public void setUserName(final String userName) {
        this.userName = userName;
    }

    /**
     * @return the deploymentServer
     */
    public DeploymentServer getDeploymentServer() {
        return deploymentServer;
    }

    /**
     * @param deploymentServer
     *            the deploymentServer to set
     */
    public void setDeploymentServer(final DeploymentServer deploymentServer) {
        this.deploymentServer = deploymentServer;
    }


    /**
     * @return the publishingRepository
     */
    public Repository getPublishingRepository() {
        return publishingRepository;
    }

    /**
     * @param publishingRepository
     *            the publishingRepository to set
     */
    public void setPublishingRepository(final Repository publishingRepository) {
        this.publishingRepository = publishingRepository;
    }

    // Logic - Justice Sara

    /**
     * this method is used to set the intiateWorkflow Properties.
     *
     * @param pProjectName
     *            - Name of the initial project
     * @param pWorkflowName
     *            - Name of the workflow
     * @param pUserName
     *            - UserName for the BCC user
     * @throws FeedProcessException
     *             - Exception thrown while processing the feed
     * @return Process the process with the new project
     */
    public Process initiateWorkflow(final String pProjectName, final String pWorkflowName, final String pUserName)
            throws FeedProcessException {
        if (isLoggingDebug()) {
            logDebug("WorkFlowTools.initiateWorkflow() started." + pWorkflowName + ", " + pProjectName + ", " + pUserName);
        }
        Process process = null;
        ProcessHome processHome = null;
        try {
            assumeUserIdentity(pUserName);
            // Getting ProcessHome reference.
            processHome = ProjectConstants.getPersistentHomes().getProcessHome();
            process = processHome.createProcessForImport(pProjectName, pWorkflowName);
            String wkspName = process.getProject().getWorkspace();
            Workspace wksp = getVersionManager().getWorkspaceByName(wkspName);
            WorkingContext.pushDevelopmentLine(wksp);
        } catch (final WorkflowException e) {
            if (isLoggingError()) {
                logError(FeedErrorMessages.WORKFLOW_EXCEPTION_INITIATE, e);
            }
            throw new FeedProcessException(FeedErrorMessages.WORKFLOW_EXCEPTION_INITIATE, e);
        } catch (final TransactionDemarcationException e) {
            if (isLoggingError()) {
                logError(FeedErrorMessages.TRANSACTION_DEMARCATION_MESSAGE, e);
            }
            throw new FeedProcessException(FeedErrorMessages.TRANSACTION_DEMARCATION_MESSAGE, e);
        } catch (final EJBException e) {
            if (isLoggingError()) {
                logError(FeedErrorMessages.EJB_EXCEPTION_INITIATE_MSG, e);
            }
            throw new FeedProcessException(FeedErrorMessages.EJB_EXCEPTION_INITIATE_MSG, e);
        } catch (final ActionException e) {
            if (isLoggingError()) {
                logError(FeedErrorMessages.ACTION_EXCEPTION_MSG, e);
            }
            throw new FeedProcessException(FeedErrorMessages.ACTION_EXCEPTION_MSG, e);
        } catch (final CreateException e) {
            if (isLoggingError()) {
                logError(FeedErrorMessages.CREATE_EXCEPTION_MSG, e);
            }
            throw new FeedProcessException(FeedErrorMessages.CREATE_EXCEPTION_MSG, e);
        } catch (final VersionException e) {
            if (isLoggingError()) {
                logError(FeedErrorMessages.VERSION_EXCEPTION_MSG, e);
            }
            throw new FeedProcessException(FeedErrorMessages.VERSION_EXCEPTION_MSG, e);
        }
        return process;
    }

    /**
     * This method is used to find the UserIdentity.
     *
     * @param pUserName
     *            - Name of the BCC user
     * @return boolean true if identity assumed correctly, otherwise false
     */
    public boolean assumeUserIdentity(final String pUserName) {
        if (isLoggingDebug()) {
            logDebug("WorkFlowTools.assumeUserIdentity(" + pUserName + ") started.");
        }
        boolean asumeUserIdentity = false;
        User newUser = null;
        Persona persona = null;
        UserAuthority userAuthority = getUserAuthority();
        if (userAuthority != null) {
            // Creating new User object.
            newUser = new User();
            persona = userAuthority.getPersona(new StringBuilder().append(getPersonaPrefix()).append(pUserName).toString());
            // Checking UserIdentity.
            if (persona != null) {
                newUser.addPersona(persona);
                ThreadSecurityManager.setThreadUser(newUser);
                if (isLoggingDebug()) {
                    logDebug("WorkFlowTools.assumeUserIdentity() ended. UserName: " + pUserName + "[" + true + "]");
                }
                asumeUserIdentity = true;
            }
        }
        if (isLoggingDebug()) {
            logDebug("WorkFlowTools.assumeUserIdentity() ended. UserName: " + pUserName + "[" + false + "]");
        }
        return asumeUserIdentity;
    }

    /**
     * Creates a project in BCC.
     *
     * @param projectName
     *            Name to identify the project.
     * @param automaticPublish
     *            Indicates if an automatic flow should be used to publish the project.
     *
     * @return the process with the new project
     */
    public Process startProjectInBCC(final String projectName, final boolean automaticPublish) {
        if (isLoggingDebug()) {
            logDebug("Inside startProjectInBCC(), ready to create project");
        }
        Process process = null;
        try {
            if (automaticPublish) {
                process = initiateWorkflow(projectName, getWorkFlowNameForAutomaticPublish(), getUserName());
            } else {
                process = initiateWorkflow(projectName, getWorkFlowName(), getUserName());
            }
        } catch (final FeedProcessException e) {
            if (isLoggingError()) {
                logError("RepositoryException occured While processing the feed", e);
            }
        }
        if (isLoggingDebug()) {
            logDebug("project created in BCC, project name: " + projectName);
            logDebug("CatalogFeedProcessor.startProjectInBCC() method Ended.");
        }
        return process;
    }

    /**
     * This method advances the workflow to the next state. If using an unaltered copy of the import-late or import-early workflows, then
     * the taskOutcomeId property should not need to be changed (default is '4.1.1'). If you are using a different workflow or an altered
     * version of the import-xxxx workflows, then the taskOutcomeId can be found in the wdl file for the respective workflow.
     *
     * @param pProcess
     *            the atg.epub.project.Process object (the project)
     * @throws MissingWorkflowDescriptionException
     *             If an error occurs
     * @throws ActorAccessException
     *             If an error occurs
     * @throws ActionException
     *             If an error occurs
     */
    public void advanceWorkflow(final Process pProcess) throws MissingWorkflowDescriptionException, ActorAccessException,
             ActionException {
        if (isLoggingInfo()) {
            logInfo("Inside advanceWorkflow(), starting automatic project publishing");
        }
        RepositoryItem processWorkflow = pProcess.getProject().getWorkflow();
        String workflowProcessName = processWorkflow.getPropertyValue("processName").toString();
        String subjectId = pProcess.getId();

        WorkflowView workflowView = getWorkflowManager().getWorkflowView(ThreadSecurityManager.currentUser());
        List<String> taskListId = getTaskListForAutoPublish();
        for (String taskId : taskListId) {
            if (isLoggingInfo()) {
                logInfo("Executing task: " + taskId);
            }
            workflowView.fireTaskOutcome(workflowProcessName, WorkflowConstants.DEFAULT_WORKFLOW_SEGMENT, subjectId, taskId,
                    ActionConstants.ERROR_RESPONSE_DEFAULT);
        }
    }

    /**
     * This method advances the workflow to the next state. If using an unaltered copy of the import-late or import-early workflows, then
     * the taskOutcomeId property should not need to be changed (default is '4.1.1'). If you are using a different workflow or an altered
     * version of the import-xxxx workflows, then the taskOutcomeId can be found in the wdl file for the respective workflow.
     *
     * @param pProcess the atg.epub.project.Process object (the project)
     * @param pTaskId The task to execute
     * @throws Exception The Exception to throw
     */
    public void advanceWorkflow(final Process pProcess, final String pTaskId) throws Exception {
        String taskId = pTaskId;
        if (isLoggingDebug()) {
            logDebug("Start inside advanceWorkflow, pProcess: " + pProcess + " taskId: " + taskId);
        }
        RepositoryItem processWorkflow = pProcess.getProject().getWorkflow();
        String workflowProcessName = processWorkflow.getPropertyValue("processName").toString();
        String subjectId = pProcess.getId();

        WorkflowView workflowView = getWorkflowManager().getWorkflowView(ThreadSecurityManager.currentUser());
        if (taskId == null) {
            taskId = getDefaultTaskId();
        }
        if (isLoggingInfo()) {
            logInfo("advanceWorkflow: Executing task: " + taskId + " for process id: " + subjectId);
        }
        workflowView.fireTaskOutcome(workflowProcessName, WorkflowConstants.DEFAULT_WORKFLOW_SEGMENT, subjectId, taskId,
                ActionConstants.ERROR_RESPONSE_DEFAULT);
        if (isLoggingDebug()) {
            logDebug("End advanceWorkflow");
        }
    }

    // Logic - Justice methods

    /**
     * This method checks for if the BCC is ready for the Feed process.
     *
     * @return null if no errors
   
     *
  
  /*
    public String checkSanityTargets() {
        if (isLoggingInfo()) {
            logInfo("checkSanityTargets started");
        }
        String message = null;
        CatalogFeedConfigurations configs = getCatalogFeedConfigurations();
        // check if the process is disable
        if (!configs.isExecuteCheckSanityTargets()) {
            return message;
        }
        try {
            assumeUserIdentity(getUserName());
            Target stagingTarget = getDeploymentServer().getTargetByName(STAGING_TARGET);
            Target productionTarget = getDeploymentServer().getTargetByName(PRODUCTION_TARGET);
            if (stagingTarget == null || productionTarget == null) {
                if (isLoggingError()) {
                    logError("Missing one target");
                }
                message = "Missing one target";
                return message;
            } else if (stagingTarget.getStatus().isStateError() || productionTarget.getStatus().isStateError()) {
                message = "Error state, staging: " + stagingTarget.getStatus().isStateError() + " production: "
                        + productionTarget.getStatus().isStateError();
                return message;
            } else if (stagingTarget.isHalted() || productionTarget.isHalted()) {
                boolean sucess = resumeDeployments();
                if (!sucess) {
                    message = "Unable to resume deployments (target halted), staging: " + stagingTarget.isHalted() + " production: "
                            + productionTarget.isHalted();
                    return message;
                }
            }
            Project[] productionDeployedActiveProjects = productionTarget.getDeployedActiveProjects(0, -1);
            List<Project> productionProjectsToRevert = new ArrayList<Project>();
            if (productionDeployedActiveProjects != null) {
                productionProjectsToRevert.addAll(Arrays.asList(productionDeployedActiveProjects));
            }
            // get the queued projects on production
            List<Project> productionQueuedProjects = getActiveProjects(productionTarget);

            // revert projects
            revertProjects(productionProjectsToRevert, PRODUCTION_TARGET);
            if (isLoggingInfo()) {
                logInfo("waiting for " + productionProjectsToRevert.size() + " projects to be reverted");
            }
            for (int i = 0; i < configs.getWaitTryNumber(); i++) {
                Thread.sleep((configs.getWaitTimeOutPerProjectSeconds() * 1000) * productionProjectsToRevert.size());
                if (productionTarget.getCountOfPendingDeployments() == 0 && productionTarget.getCountOfQueuedDeployments() == 0) {
                    if (isLoggingInfo()) {
                        logInfo("Revert process in production complete: " + i);
                    }
                    break;
                }
                if (isLoggingInfo()) {
                    logInfo("Wait try number: " + i);
                }
                if (i == configs.getWaitTryNumber() - 1) {
                    message = "Unable to revert all the projects from Production (timeout)";
                    return message;
                }
            }
            // COMPLETED REVERT PROJECTS FROM PRODUCTION
            // Start staging revert
            List<Project> stagingProjectsToRevert = new ArrayList<Project>();
            Project[] stagingDeployedActiveProjects = stagingTarget.getDeployedActiveProjects(0, -1);
            if (null != stagingDeployedActiveProjects) {
                stagingProjectsToRevert.addAll(Arrays.asList(stagingDeployedActiveProjects));
            }
            // add production projects and remove duplicated
            stagingProjectsToRevert.removeAll(productionProjectsToRevert);
            stagingProjectsToRevert.addAll(productionProjectsToRevert);
            // add production queued projects
            stagingProjectsToRevert.removeAll(productionQueuedProjects);
            stagingProjectsToRevert.addAll(productionQueuedProjects);

            // get queued projects on staging, just to remove the deployment
            getActiveProjects(stagingTarget);
            // revertProjectsFromProduction
            revertProjects(stagingProjectsToRevert, STAGING_TARGET);
            // wait revert
            if (isLoggingInfo()) {
                logInfo("waiting for " + stagingProjectsToRevert.size() + " projects to be reverted");
            }
            for (int i = 0; i < configs.getWaitTryNumber(); i++) {
                Thread.sleep((configs.getWaitTimeOutPerProjectSeconds() * 1000) * stagingProjectsToRevert.size());
                if (stagingTarget.getCountOfPendingDeployments() == 0 && stagingTarget.getCountOfQueuedDeployments() == 0) {
                    Project[] activeProjectsStaging = stagingTarget.getDeployedActiveProjects(0, -1);
                    if (activeProjectsStaging == null || activeProjectsStaging.length == 0) {
                        if (isLoggingInfo()) {
                            logInfo("Revert process in staging complete: " + i);
                        }
                        break;
                    } else if (activeProjectsStaging != null) {
                        message = "There is one or more projects stuck that we can't revert:<br>";
                        for (Project activeProject : activeProjectsStaging) {
                            message += activeProject.getId() + ":" + activeProject.getDisplayName() + "<br>";
                        }
                        return message;
                    }
                }
                if (isLoggingInfo()) {
                    logInfo("Wait try number: " + i);
                }
                if (i == configs.getWaitTryNumber() - 1) {
                    message = "Unable to revert all the projects from Staging (timeout)";
                    return message;
                }
            }
        } catch (final Exception e) {
            if (e.getMessage() != null) {
                message = e.getMessage();
            } else {
                message = "Critical Error. See logs for details: " + e.getCause();
            }
            if (isLoggingError()) {
                logError(e);
            }
        } finally {
            if (isLoggingInfo()) {
                logInfo("checkSanityTargets result: " + message);
            }
        }
        return message;
    }
    */

    /**
     * This method can halt the deployments of all the targets
     * @return Return true if success
     */
    public boolean haltDeployments() {
        boolean success = true;
        try {
            Target[] targets = getDeploymentServer().getTargets();
            if(targets != null) {
                for (Target target : targets) {
                    target.haltQueue();
                }
            }
        } catch (Exception e) {
            if (isLoggingError()) {
                logError(e);
            }
            success = false;
        }
        return success;
    }

    /**
     * This method can resume the deployments of all the targets.
     *
     * @return return true if success
     */
    public boolean resumeDeployments() {
        boolean success = true;
        try {
            Target[] targets = getDeploymentServer().getTargets();
            if (targets != null) {
                for (Target target : targets) {
                    target.resumeQueue();
                }
            }
        } catch (final Exception e) {
            if (isLoggingError()) {
                logError(e);
            }
            success = false;
        }
        return success;
    }

    /**
     * This method gets the all the projects in the queue and in the To Do list and cancel the projects from the queue list and To Do plan.
     *
     * @param target
     *            The target to analyze.
     * @return Return a list of active projects from the targets.
     * @throws Exception
     *             Throws exceptions if error happens.
     */
    @SuppressWarnings("unchecked")
    protected List<Project> getActiveProjects(final Target target) throws Exception {
        final ProjectHome projectHome = ProjectConstants.getPersistentHomes().getProjectHome();
        List<Project> projects = new ArrayList<Project>();

        // get all the projects in the plan
        projects.addAll(getProjectsAndDeleteDeployment(target.getPendingDeployments(0, -1)));
        projects.addAll(getProjectsAndDeleteDeployment(target.getQueuedDeployments(0, -1)));
        projects.addAll(getProjectsAndDeleteDeployment(target.getScheduledDeployments(0, -1)));

        // get the projects approved to target - To Do section
        Collection<Project> projectsApprovedForTarget = projectHome.findByDeploymentStatus(target.getID(),
                Deployment.APPROVED_FOR_TARGET, 0, -1);
        if (projectsApprovedForTarget != null) {
            for (Project projectApprovedForTarget : projectsApprovedForTarget) {
                projects.add(projectApprovedForTarget);
                projectApprovedForTarget.revokeDeploymentApproval(target);
            }
        }

        return projects;
    }

    /**
     * Reverts all the projects from a specific target.
     *
     * @param productionProjects
     *            The list of project to revert.
     * @param env
     *            The target to revert [Staging|Production].
     * @throws Exception
     *             If an error occurs
     */
    protected void revertProjects(final List<Project> productionProjects, final String env) throws Exception {
        if (productionProjects != null) {
            for (Project project : productionProjects) {
                revertProject(project, env);
            }
        }
    }

    /**
     * This method returns a list of projects from a deployment and deletes the project from the To Do list or plan.
     *
     * @param deployments
     *            The deployments to loop to get the projects.
     * @return Return a list of active projects from the deployments.
     * @throws Exception
     *             Throws exceptions if error happens.
     */
    private List<Project> getProjectsAndDeleteDeployment(final Deployment[] deployments) throws Exception {
        List<Project> projects = new ArrayList<Project>();
        if (deployments != null) {
            for (Deployment deployment : deployments) {
                projects.addAll(getProjectsFromDeployment(deployment));
                deleteDeployment(deployment);
            }
        }
        return projects;
    }

    /**
     * This method reverts a project from a specific target.
     *
     * @param project
     *            The project to revert.
     * @param env
     *            The target to revert.
     * @throws Exception
     *             If an error occurs
     * @throws MissingWorkflowDescriptionException
     */
    private void revertProject(final Project project, final String env) throws Exception {
        if (isLoggingInfo()) {
            logInfo("Reverting project id: " + project.getId() + " name: " + project.getDisplayName() + " from " + env);
        }
        // assumeUserIdentity("publishing");
        RepositoryItem processWorkflow = project.getWorkflow();
        String workflowProcessName = processWorkflow.getPropertyValue("processName").toString();
        String subjectId = getProcessIdByProjectId(project.getId());
        // if null try with the regular id
        if (StringUtils.isEmpty(subjectId)) {
            subjectId = "prc" + project.getId().substring(3, project.getId().length());
        }
        WorkflowViewImpl workflowView = (WorkflowViewImpl) getWorkflowManager().getWorkflowView(ThreadSecurityManager.currentUser());
        WorkflowDescriptor workflow = workflowView.getDefinitionRegistry().getWorkflowDescriptor(workflowProcessName,
                WorkflowConstants.DEFAULT_WORKFLOW_SEGMENT);
        OutcomeDescriptor outcomeTask = null;
        // check if the project is the regular workflow
        if ("/Common/commonWorkflow.wdl".equalsIgnoreCase(workflowProcessName)) {
            TaskDescriptor taskDescriptor = workflow.getTaskByName("verify" + env);
            if (env.equalsIgnoreCase(PRODUCTION_TARGET)) {
                outcomeTask = taskDescriptor.getOutcomeByName("revertAssetsOnlyOnProductionNow");
            } else {
                outcomeTask = taskDescriptor.getOutcomeByName("revertAssetsOnStagingNow");
            }
            // if staging remove the staging approval
            if (STAGING_TARGET.equalsIgnoreCase(env)) {
                taskDescriptor = workflow.getTaskByName("productionApproval");
                OutcomeDescriptor rejectOutcomeTask = taskDescriptor.getOutcomeByName("reject");
                workflowView.fireTaskOutcome(workflowProcessName, WorkflowConstants.DEFAULT_WORKFLOW_SEGMENT, subjectId,
                        rejectOutcomeTask.getOutcomeElementId(), ActionConstants.ERROR_RESPONSE_DEFAULT);
            }
            workflowView.fireTaskOutcome(workflowProcessName, WorkflowConstants.DEFAULT_WORKFLOW_SEGMENT, subjectId,
                    outcomeTask.getOutcomeElementId(), ActionConstants.ERROR_RESPONSE_DEFAULT);
        } else {
            if (isLoggingError()) {
                logError("Found a project with a different workflow " + workflowProcessName);
            }
        }
    }

    /**
     * This method returns a list of projects from a deployment.
     *
     * @param deployment
     *            The deployment to get the projects.
     * @return Return a list of active projects from the deployment.
     * @throws Exception
     *             Throws exceptions if error happens.
     */
    private List<Project> getProjectsFromDeployment(final Deployment deployment) throws Exception {
        final ProjectHome projectHome = ProjectConstants.getPersistentHomes().getProjectHome();
        List<Project> projects = new ArrayList<Project>();
        for (String projectId : deployment.getProjectIDs()) {
            projects.add(projectHome.findById(projectId));
        }
        return projects;
    }

    /**
     * This method deletes a deployment from queue of a target.
     *
     * @param deployment
     *            The deployment to delete.
     * @return Return true if success.
     */
    private boolean deleteDeployment(final Deployment deployment) {
        boolean success = true;
        final ProjectHome projectHome = ProjectConstants.getPersistentHomes().getProjectHome();
        try {
            Project project = projectHome.findById(deployment.getProjectIDs()[0]);
            RepositoryItem processWorkflow = project.getWorkflow();
            String workflowProcessName = processWorkflow.getPropertyValue("processName").toString();
            // we should only remove deploymets from workflows we know
            if ("/Common/commonWorkflow.wdl".equalsIgnoreCase(workflowProcessName)) {
                assumeUserIdentity("admin");
                String loginName = "admin";
                AgentRef[] agents = deployment.getAccessibleAgents();
                deployment.delete(loginName);
                if (agents != null) {
                    for (AgentRef agentRef : agents) {
                        agentRef.cancelDeployment(deployment.getDeploymentID());
                    }
                }
            }
        } catch (final Exception e) {
            if (isLoggingError()) {
                logError(e);
            }
            success = false;
        }
        return success;
    }

    /**
     * We found an issue, normally the projects and the process has the same number, but in some ocations we saw different id so we query
     * the process to get the right id.
     *
     * @param projectId
     *            The project id to query
     * @return The process id
     */
    private String getProcessIdByProjectId(final String projectId) {
        try {
            RepositoryView view = getPublishingRepository().getView("process");
            QueryBuilder qb = view.getQueryBuilder();
            Query[] queries = new Query[1];

            QueryExpression qe1 = qb.createPropertyQueryExpression("project.id");
            QueryExpression qe2 = qb.createConstantQueryExpression(projectId);

            queries[0] = qb.createPatternMatchQuery(qe1, qe2, QueryBuilder.EQUALS);

            Query submittedOrderQuery = qb.createOrQuery(queries);
            RepositoryItem[] items = view.executeQuery(submittedOrderQuery);
            if (items != null && items.length > 0) {
                return items[0].getRepositoryId();
            }
        } catch (final Exception e) {
            if (isLoggingError()) {
                logError(e);
            }
        }
        return null;
    }
}

